{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[2],\n",
       "        [3],\n",
       "        [4]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = torch.tensor([2,3,4])\n",
    "b.size()\n",
    "b.unsqueeze(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([3, 5])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = torch.tensor([[0.1,0.1,0.3,0.2,0.3],\n",
    "                  [0.4,0.4,0.1,0.05,0.05],\n",
    "                  [0.1,0.1,0.1,0.2,0.5]])\n",
    "a.size()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.3000],\n",
       "        [0.0500],\n",
       "        [0.5000]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = torch.gather(a, 1, b.unsqueeze(1))\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[-1.2040],\n",
       "        [-2.9957],\n",
       "        [-0.6931]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.log(c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.6931471805599453"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "math.log(0.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 如何计算多分类的交叉熵损失？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_true = ['1', '4', '5'] # 样本的真实标签\n",
    "\n",
    "y_pred = [\n",
    "    [0.1, 0.6, 0.3, 0, 0, 0, 0, 0, 0, 0],\n",
    "    [0, 0.3, 0.2, 0, 0.5, 0, 0, 0, 0, 0],\n",
    "    [0.6, 0.3, 0, 0, 0, 0.1, 0, 0, 0, 0]\n",
    "]            \n",
    "# 样本的预测概率\n",
    "labels = ['0','1','2','3','4','5','6','7','8','9'] # 所有标签"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import log_loss\n",
    "from sklearn.preprocessing import LabelBinarizer\n",
    "from math import log"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loss by sklearn is:1.1688526324400008.\n"
     ]
    }
   ],
   "source": [
    "# 利用sklearn中的log_loss()函数计算交叉熵\n",
    "sk_log_loss = log_loss(y_true, y_pred, labels=labels)\n",
    "print(\"Loss by sklearn is:%s.\" %sk_log_loss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0 1 0 0 0 0 0 0 0 0]\n",
      " [0 0 0 0 1 0 0 0 0 0]\n",
      " [0 0 0 0 0 1 0 0 0 0]]\n",
      "0\n",
      "0.1\n",
      "---\n",
      "1\n",
      "0.6\n",
      "---\n",
      "0\n",
      "0.3\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "0.3\n",
      "---\n",
      "0\n",
      "0.2\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "1\n",
      "0.5\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "0.6\n",
      "---\n",
      "0\n",
      "0.3\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "1\n",
      "0.1\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "0\n",
      "1e-15\n",
      "---\n",
      "Loss by equation is:1.1688526324399937.\n"
     ]
    }
   ],
   "source": [
    "# 对样本的真实标签进行标签二值化\n",
    "lb = LabelBinarizer()\n",
    "lb.fit(labels)\n",
    "transformed_labels = lb.transform(y_true)\n",
    "print(transformed_labels)\n",
    "\n",
    "N = len(y_true)  # 样本个数\n",
    "K = len(labels)  # 标签个数\n",
    "\n",
    "eps = 1e-15      # 预测概率的控制值\n",
    "Loss = 0         # 损失值初始化\n",
    "\n",
    "for i in range(N):\n",
    "    for k in range(K):\n",
    "        # 控制预测概率在[eps, 1-eps]内，避免求对数时出现问题\n",
    "        if y_pred[i][k] < eps:\n",
    "            y_pred[i][k] = eps\n",
    "        if y_pred[i][k] > 1-eps:\n",
    "            y_pred[i][k] = 1-eps\n",
    "        # 多分类问题的交叉熵计算公式\n",
    "        print(transformed_labels[i][k])\n",
    "        \n",
    "        print(y_pred[i][k])\n",
    "        print(\"---\")\n",
    "        Loss -= transformed_labels[i][k]*log(y_pred[i][k])\n",
    "\n",
    "Loss /= N\n",
    "print(\"Loss by equation is:%s.\" % Loss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = torch.gather(torch.tensor(y_pred), 1, torch.tensor([int(i) for i in y_true], dtype=torch.long).unsqueeze(1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.5108],\n",
       "        [0.6931],\n",
       "        [2.3026]])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "-torch.log(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.5065"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2.3026+0.5108+0.6931"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
